mongodb = require 'mongodb'
ObjectId = mongodb.ObjectId
MongoClient = mongodb.MongoClient
Promise = require 'bluebird'

log = require '../log'
config = require "../config"

pConnect = Promise.promisify MongoClient.connect

dbQs = {}

pGetOrConnect = (tag, url)->
    return dbQs[tag] if dbQs[tag]?

    q = pConnect url
    q.then (db)->
        dbQs[tag] = q
        db.on 'close', ->
            log.system.info 'Mongo DB closed'
            delete dbQs[tag]
        db.on 'error', (e)->
            log.system.error e, 'Mongo DB error'
            delete dbQs[tag]
        db.on 'reconnect', ->
            log.system.info 'Mongo DB reconnect'

    return q

exports.pDatabase = -> pGetOrConnect 'main', config.mainMongoUrl

exports.gDispose = ->
    for key, q of dbQs
        try
            db = yield q
            yield db.close()
        catch e
            log.system.error e, 'end mongodb'

# 返回值是ObjectId
exports.getInsertedIdObject = (r)->
    return r?.insertedId || null

exports.getUpdateResult = (r)->
    {matchedCount: r.matchedCount, modifiedCount: r.modifiedCount}

ErrorCodes =
    Index: 11000

exports.isIndexConflictError = (e)->
    return e.code == ErrorCodes.Index

exports.stringToObjectId = (string)->
    return null unless string
    if string instanceof ObjectId
        string
    else
        new ObjectId string

# 可能返回 null / undefined
exports.stringToObjectIdSilently = (string)->
    return string if string instanceof ObjectId

    return string unless string? # 原样返回 null/undefined

    try
        new ObjectId string
    catch
        undefined

exports.stringArrayToObjectIdArraySilently = (strings)->
    return [] unless strings?
    ids = []
    for s in strings
        id = exports.stringToObjectIdSilently s
        ids.push id if id?
    return ids

exports.toMongoCriteria = (criteria, mongoCriteria)->
    return unless criteria?

    if criteria.relation
        if criteria.relation == 'or'
            items = []
            for item in criteria.items
                mc = {}
                exports.toMongoCriteria item, mc
                items.push mc if mc
            mongoCriteria['$or'] = items
        else
            for item in criteria.items
                exports.toMongoCriteria item, mongoCriteria
    else if criteria.field
        operator = criteria.operator
        value = criteria.value
        field = criteria.field
        fc = mongoCriteria[field] = mongoCriteria[field] || {}
        switch operator
            when '=='
                mongoCriteria[field] = value
            when '!='
                fc.$ne = value # TODO 对于部分运算符要检查 comparedValue 不为 null/undefined/NaN
            when '>'
                fc.$gt = value
            when '>='
                fc.$gte = value
            when '<'
                fc.$lt = value
            when '<='
                fc.$lte = value
            when 'in'
                fc.$in = value
            when 'nin'
                fc.$nin = value
            when 'start'
                fc.$regex = "^" + value
            when 'end'
                fc.$regex = value + "$"
            when 'contain'
                fc.$regex = value

test = ->
    criteria1 = {field: "name", operator: '==', value: '1'}
    criteria2 = {
        relation: 'and',
        items: [{field: "name", operator: '==', value: '1'}, {field: "age", operator: '>=', value: 100},
            {field: "age", operator: '<', value: 200}]
    }
    criteria3 = {
        relation: 'and',
        items: [
            {field: "name", operator: '==', value: '1'},
            {
                relation: 'or',
                items: [{field: 'jl', operator: '==', value: true}, {field: 'xl', operator: '==', value: true}]
            }
        ]
    }
    mongoCriteria = {}
    exports.toMongoCriteria criteria3, mongoCriteria
    console.log mongoCriteria